package cn.com.bsfit.netty.req;

import cn.com.bsfit.netty.exception.DefaultException;
import cn.com.bsfit.netty.resp.BaseResponseUtils;
import cn.com.bsfit.netty.utils.SpringBeanUtil;
import cn.com.bsfit.netty.utils.StringHelper;
import cn.com.bsfit.netty.utils.XmlToMapUtil;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import cn.com.bsfit.netty.task.JsonReq2DataTask;
import cn.com.bsfit.netty.task.Req2MapTaskRs;
import cn.com.bsfit.netty.task.XmlReq2DataTask;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;

/**
 * 类名 ReqData2MapFacade
 * 描述 请求数据转化为Map的Facade
 *
 * @author hedonglin
 * @version 1.0
 * @date 2019/9/27 10:33
 */
@Slf4j
public class ReqData2MapFacade{
    /**
     * 是否是Json的标志
     */
    private boolean isJson = false;
    /**
     * 是否是Xml的标志
     */
    private boolean isXml = false;
    /**
     * 是否是顶层非空的且不在jsonReqFormat.getTopField中
     */
    private boolean notInTopField = false;

    /**
     * 当前顶层字段
     */
    private String currTopField = "";

    private Map<String, ReqData2MapStrategy> reqData2MapStrategyMap;
    private DefaultReqDataFormat jsonReqFormat;

    public ReqData2MapFacade(Map<String, ReqData2MapStrategy> reqData2MapStrategyMap, DefaultReqDataFormat jsonReqFormat) {
        this.reqData2MapStrategyMap = reqData2MapStrategyMap;
        this.jsonReqFormat = jsonReqFormat;
    }

    /**
     * 方法描述: Facade提供一个将请求数据转化为Map的功能
     *
     * @param msg 请求数据
     * @return {@link Map} Map
     * @author hedonglin
     * @date 2019/9/25 15:10
     */
    public Map<String, Object> reqDataToMap(String msg) throws DefaultException {
        // 多任务转化请求数据
        List<Callable<Req2MapTaskRs>> tasks = new ArrayList<>();
        // 初始化数据格式
        isJson = false;
        isXml = false;

        // 遍历转换策略
        for (ReqData2MapStrategy strategy : reqData2MapStrategyMap.values()) {
            if (strategy instanceof JsonReqData2Map){
                tasks.add(new JsonReq2DataTask(msg, strategy));
            }else  if (strategy instanceof XmlReqData2Map){
                tasks.add(new XmlReq2DataTask(msg, strategy));
            }
        }

        try {
            // 获取线程池的Bean
            ExecutorService transExecutor = (ExecutorService) SpringBeanUtil.getBean("dataTransactionPool");
            // 多任务转换数据
            List<Future<Req2MapTaskRs>> futures = transExecutor.invokeAll(tasks);
            Req2MapTaskRs successRs = null;
            for (Future<Req2MapTaskRs> r : futures) {
                try {
                    if (r.get() == null) {
                        throw new DefaultException("数据转化异常");
                    }
                    Req2MapTaskRs req2MapTaskRs = r.get();
                    if (req2MapTaskRs.isSuccess()) {
                        successRs = r.get();
                    }if (!StringUtils.isEmpty(req2MapTaskRs.getCurrentTopField())){
                        currTopField = req2MapTaskRs.getCurrentTopField();
                    }
                } catch (InterruptedException | ExecutionException e) {
                    log.error("数据转化异常:{}" + e);
                }
            }

            if (successRs == null){
                throw new DefaultException("非法数据格式");
            }
            if (successRs.isJson()) {
                // 设置为是json
                isJson = true;
            } else if (successRs.isXml()) {
                // 设置为是xml
                isXml = true;
            }
            if (StringHelper.isNotBlank(successRs.getCurrentTopField()) &&
                    !jsonReqFormat.getTopField().contains(successRs.getCurrentTopField())){
                notInTopField = true;
                log.warn("当前消息的顶层标签存在且不属于配置的顶层标签");
            }
            return successRs.getResultData();
        } catch (Exception e) {
            log.error("非法数据格式:{}" + e);
        }

        throw new DefaultException("请求数据格式校验不通过");
    }

    /**
     * 方法描述: 从请求中获取首部字段的Key字段
     *
     * @param reqMap 请求Map
     * @return {@link String} key
     * @author hedonglin
     * @date 2019/9/29 16:14
     */
    public String getReqMapHead(Map<String, Object> reqMap) {
        return getReqMapHeadOrBody(reqMap, true, false);
    }

    /**
     * 方法描述: 从请求中获取主体字段的Key字段
     *
     * @param reqMap 请求Map
     * @return {@link String} key
     * @author hedonglin
     * @date 2019/9/29 16:14
     */
    public String getReqMapBody(Map<String, Object> reqMap) {
        return getReqMapHeadOrBody(reqMap, false, true);
    }

    /**
     * 方法描述: 从请求中获取首部/主体字段的Key字段
     *
     * @param reqMap 请求Map
     * @return {@link String} key
     * @author hedonglin
     * @date 2019/9/29 16:14
     */
    public String getReqMapHeadOrBody(Map<String, Object> reqMap, boolean isHead, boolean isBody) {
        String result = "";
        if (reqMap == null) {
            return result;
        }

        List<String> field = new ArrayList<>();
        if (isHead) {
            field = jsonReqFormat.getHeadField();
        } else if (isBody) {
            field = jsonReqFormat.getBodyField();
        }
        for (String key : field) {
            if (reqMap.containsKey(key)) {
                return key;
            }
        }
        return result;
    }

    /**
     * 方法描述: 从请求中获取Head
     * @param reqMap 请求Map
     * @author hedonglin
     * @date 2019/9/29 16:22
     * @return {@link Map} Map
    */
    public Map<String, Object> getReqMapHeadMap(Map<String, Object> reqMap) {
        return getReqMapHeadOrBodyMap(reqMap, true, false);
    }

    /**
     * 方法描述: 从请求中获取Body
     * @param reqMap 请求Map
     * @author hedonglin
     * @date 2019/9/29 16:22
     * @return {@link Map} Map
     */
    public Map<String, Object> getReqMapBodyMap(Map<String, Object> reqMap) {
        return getReqMapHeadOrBodyMap(reqMap, false, false);
    }

    /**
     * 方法描述: 从请求中获取Head或Body
     * @param reqMap 请求Map
     * @author hedonglin
     * @date 2019/9/29 16:22
     * @return {@link Map} Map
     */
    public Map<String, Object> getReqMapHeadOrBodyMap(Map<String, Object> reqMap, boolean isHead, boolean isBody) {
        if (reqMap == null){
            reqMap = Collections.emptyMap();
        }
        Map<String, Object> result = Maps.newHashMap();
        List<String> field = Lists.newArrayList();
        if (isHead) {
            field = jsonReqFormat.getHeadField();
        } else if (isBody) {
            field = jsonReqFormat.getBodyField();
        }
        for (String key : field) {
            Object o = reqMap.get(key);
            if (o == null){
                continue;
            }
            if (o instanceof Map) {
                return (Map<String, Object>) o;
            }
        }
        return result;
    }

    /**
     * 方法描述: 合并Head和Body
     * @param reqMap 请求Map
     * @author hedonglin
     * @date 2019/9/29 16:27
     * @return {@link Map< String, Object>} Map
    */
    public Map<String, Object> mergeHeadBody(Map<String, Object> reqMap){
        Map<String, Object> result = Maps.newHashMap();

        Map<String, Object> headMap = getReqMapHeadMap(reqMap);
        Map<String, Object> bodyMap = getReqMapBodyMap(reqMap);

        if (headMap.size() == 0 && bodyMap.size() == 0){
            return reqMap;
        }

        if (headMap.size() > 0){
            result.putAll(headMap);
        }

        if (bodyMap.size() > 0){
            result.putAll(bodyMap);
        }

        return result;
    }


    /**
     * 方法描述: 将结果Map转换为JSON/XML
     *
     * @param reqMap ETL/引擎请求Map
     * @param baseResponse ETL/引擎返回的结果Map的Body部分
     * @return {@link String} 字符串结果
     * @author hedonglin
     * @date 2019/9/27 14:56
     */
    public String resMapToStr(boolean isJson, Map<String, Object> reqMap,
                              Map<String, Object> baseResponse,
                              boolean isContainsTop,
                              boolean isContainsHead,
                              boolean isContainsBody) {

        try {
            String currTopField = isContainsTop ? getCurrTopField() : "";
            String currHeadFiel = isContainsHead ? getReqMapHead(reqMap) : "";
            String currBodyField = isContainsBody ? getReqMapBody(reqMap) : "";



            // 构造返回结果
            Map<String, Object> resMap = BaseResponseUtils.successIsContains(isJson, getReqMapHeadMap(reqMap), baseResponse,
                    currTopField, currHeadFiel, currBodyField);

            if (resMap != null) {
                if (isJson) {
                    // 转换为JSON
                    return JSONObject.toJSONString(resMap,
                            SerializerFeature.WriteDateUseDateFormat,
                            SerializerFeature.DisableCircularReferenceDetect);
                } else if (isXml) {
                    //转化为XML
                    return XmlToMapUtil.formatXml1(XmlToMapUtil.map2xml(resMap));
                }
            }
        } catch (Exception e) {
            log.error("transError: {}", e == null ? "数据格式验证失败" : e.getMessage());
        }

        Map<String, Object> defaultResMap = BaseResponseUtils.successIsContains(isJson, getReqMapHeadMap(reqMap), baseResponse,
                currTopField == null ? "" : currTopField , "", "");
        try {
            return XmlToMapUtil.formatXml1(XmlToMapUtil.map2xml(defaultResMap));
        } catch (Exception e) {
            log.error("transError: {}", "将返回数据转换为XML失败");
            return JSONObject.toJSONString(defaultResMap);
        }
    }

    public boolean isJson() {
        return isJson;
    }

    public void setJson(boolean json) {
        isJson = json;
    }

    public boolean isXml() {
        return isXml;
    }

    public void setXml(boolean xml) {
        isXml = xml;
    }

    public boolean isNotInTopField() {
        return notInTopField;
    }

    public void setNotInTopField(boolean notInTopField) {
        this.notInTopField = notInTopField;
    }

    public String getCurrTopField() {
        return currTopField;
    }

    public void setCurrTopField(String currTopField) {
        this.currTopField = currTopField;
    }

}
